/**
 * 微信公众号，接受微信后台推送信息的服务
 */
import { Builder, convertableToString, OptionsV2, parseString } from 'xml2js';
import { ICommonParams } from '@feidao/service/interfaces';
import log from '@feidao/web/atom/nodejs/logger/log';

interface IWxMsg {
	ToUserName: string;
	FromUserName: string;
	CreateTime: number;
	MsgType: string;
	MsgId: number;

	Content?: string;

	PicUrl?: string;
	MediaId?: string;

	Format?: any;
	MediaID?: string;

	Event?: string;
	EventKey?: string;
}

interface IXmlJson {
	xml: IWxMsg;
}


/**
 * 将xml转为JSON
 * @param xml_str xml字符串
 * @param options 配置
 */
function xml2json(_xml_str: convertableToString, options: OptionsV2) {
	return new Promise<IXmlJson>((resolve, reject) => {
		parseString(_xml_str, options, (err, _result) => {
			if (err) {
				const err_msg = (err && err.toString()) || 'unknow';
				log(`parse xml:${_xml_str}.error msg: ${err_msg}`);
				reject(err_msg);
			} else {
				resolve(_result);
			}
		});
	});
}

/**
 * 将JSON转为xml
 * @param obj JSON
 * @param options 配置
 */
function json2xml(obj: any, options: OptionsV2) {
	const builder = new Builder(options);
	const _xml_result = builder.buildObject(obj);
	return _xml_result;
}

async function switchToFrom(obj: IWxMsg) {
	const toUserName = obj.ToUserName;
	const fromUserName = obj.FromUserName;
	obj.ToUserName = fromUserName;
	obj.FromUserName = toUserName;
	return obj;
}

/**
 *
 * @param msg 微信普通消息
 * @param spaceid
 */
async function commonMsgHandle(msg: IXmlJson, _spaceid: string) {
	let xml_obj = msg.xml;
	let _result: any = '';
	let service_name = null;
	switch (xml_obj.MsgType) {
		case 'text':
			// 文本类型
			service_name = 'wx_text';
			break;
		case 'image':
			// 图片消息
			service_name = 'wx_image';
			break;
		case 'voice':
			// 语音消息
			service_name = 'wx_voice';
			break;
		case 'video':
			// 视频消息
			service_name = 'wx_video';
			break;
		case 'shortvideo':
			// 小视频消息
			service_name = 'wx_shortvideo';
			break;
		case 'location':
			// 地理位置消息
			service_name = 'wx_location';
			break;
		case 'link':
			// 链接消息
			service_name = 'wx_link';
			break;
		default:
			// 其他类型转发到客服接口
			xml_obj = await switchToFrom(xml_obj);
			xml_obj.MsgType = 'transfer_customer_service';
			_result = msg;
			break;
	}
	if (!service_name || !_spaceid) {
		const err_msg = `not support eventtype:${xml_obj.Event}`;
		log(err_msg);
		return '';
	}
	return _result;
}


/**
 * 处理微信事件消息，转发到drools自定义服务中，这里不做处理只获取需要的内容
 * @param msg
 */
function eventMsgHandle(msg: IXmlJson, spaceid: string) {
	log('get event msg info:', JSON.stringify(msg));
	const xml_obj = msg && msg.xml;
	let service_name = null;
	const event_key = xml_obj.EventKey;
	switch (xml_obj.Event) {
		case 'subscribe':
			// 关注公众号
			service_name = 'wx_subscribe';
			// TODO 参考示例
			subscribe(xml_obj, spaceid);
			break;
		case 'unsubscribe':
			service_name = 'wx_unsubscribe';
			// 取消关注公众号
			break;
		case 'CLICK':
			service_name = 'wx_click_menu';
			// 用户点击自定义菜单事件
			break;
		case 'VIEW':
			service_name = 'wx_url_menu';
			// 用户点击菜单跳转
			break;
		case 'LOCATION':
			// 上报地理位置事件
			service_name = 'wx_location_event';
			break;
		case 'SCAN':
			// 用户已关注时的扫一扫事件
			service_name = 'wx_scan';
			break;
		default:
			break;
	}
	if (!service_name || !spaceid) {
		const err_msg = `not support eventtype:${xml_obj.Event}`;
		log(err_msg);
		return '';
	}
	return '';
}

async function subscribe(xml_obj: IWxMsg, _spaceid: string) {
	// todo 做关注的相关处理，其他类型的事件或者文本，可以按照这种方式调用。
}

/**
 * 处理微信回调消息。微信回调消息地址都是同一个地址，这里对普通用户消息和事件消息分开处理
 * @param msg 微信回调传递的参数
 */
async function msgHandle(msg: IXmlJson, _spaceid: string) {
	const xml_obj = msg && msg.xml;
	if (xml_obj.MsgId) {
		// 普通用户消息
		return await commonMsgHandle(msg, _spaceid);
	} else if (xml_obj.MsgType === 'event') {
		// 事件推送消息
		return eventMsgHandle(msg, _spaceid);
	} else {
		return Promise.reject('not avaliable msg');
	}
}

export default async function atom(msg: ICommonParams, action_id: string, session_id: string, spaceid: string) {
	// 获取第三方（微信）回调的参数
	const xml_str = msg.data;
	const headers = msg.headers;
	log(`receive msg from wx:${xml_str}`, '');
	// 将xml转换为JSON
	const result = await xml2json(xml_str, { explicitArray: false });
	const handle_result = await msgHandle(result, spaceid);
	const xml_result = handle_result && json2xml(handle_result, { cdata: true, headless: true });
	log('send result to wx:', xml_result);
	return { data: xml_result };
}
